﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Xml;
using System.IO;
using IRDev.Library.ExpandedException.Factory;



//Mark Rowe Sept 25, 2010
namespace AutoDeploy.Common.Library
{
    static class XPathHelper
    {
        /// <summary>
        /// Add Element to an XElement from and XPath Expression
        /// </summary>
        /// <param name="x">The Xml Object that will be inserted too.</param>
        /// <param name="xPathExpression">XPath of the Element to add</param>
        /// <param name="valueToAdd">The value of the new Element</param>
        /// <param name="namespaces">In format prefix::NameSpaceURI</param>
        /// <returns></returns>
        public static XElement AddElementFromXPath(this XElement x, string xPathExpression, string valueToAdd, List<string> namespaces)
        {
            //Params
            List<string> Params = new List<string>();
            Params.Add(string.Format("XElement x:{0}",x.ToString()));
            Params.Add(string.Format("String xPathExpression:{0}",xPathExpression));
            Params.Add(string.Format("String valueToAdd:{0}",valueToAdd));
            Params.Add(string.Format("List<String>  namespaces:{0}", StringHelper.ListOfStringToString(namespaces, true)));
            try
            {
                List<string> lst = new List<string>();
                XmlReader reader = XmlReader.Create(new StringReader(x.ToString()));
                XElement root = XElement.Load(reader);
                XmlNameTable nameTable = reader.NameTable;
                XmlNamespaceManager nsm = new XmlNamespaceManager(nameTable);
                foreach (string t in namespaces)
                {
                    lst = t.StringToListOfString("::", true, false);
                    nsm.AddNamespace(lst[0], lst[1]);
                }
                return x.AddElementToElementUsingXPath(xPathExpression, valueToAdd, nsm);
            }
            catch (IRDev.Library.ExpandedException.Common.ExpandedException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                IRDev.Library.ExpandedException.Common.ExpandedException ee = IRDev.Library.ExpandedException.Factory.ExpandedExceptionFactory.CreateAndReturnExpandedException(ex, StringHelper.ListOfStringToString(Params, true), "XPathHelper", "AddElementFromXPath");
                throw ee;
            }
        }
        /// <summary>
        /// Add Element to an XElement from and XPath Expression
        /// </summary>
        /// <param name="x">The Xml Object that will be inserted too.</param>
        /// <param name="xPathExpression">XPath of the Element to add</param>
        /// <param name="valueToAdd">The value of the new Element</param>
        /// <returns>Changed XElement</returns>
        public static XElement AddElementFromXPath(this XElement x, string xPathExpression, string valueToAdd)
        {
            //Params
            List<string> Params = new List<string>();
            Params.Add(string.Format("XElement x:{0}", x.ToString()));
            Params.Add(string.Format("String xPathExpression:{0}", xPathExpression));
            Params.Add(string.Format("String valueToAdd:{0}", valueToAdd));
            try
            {
                List<string> ls = new List<string>();
                return AddElementFromXPath(x, xPathExpression, valueToAdd, ls);
            }
            catch (IRDev.Library.ExpandedException.Common.ExpandedException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                IRDev.Library.ExpandedException.Common.ExpandedException ee = IRDev.Library.ExpandedException.Factory.ExpandedExceptionFactory.CreateAndReturnExpandedException(ex, StringHelper.ListOfStringToString(Params, true), "XPathHelper", "AddElementFromXPath");
                throw ee;
            }
        }
        /// <summary>
        /// Adds or Edits Attribute if it already existed. Based on XPath Statement.
        /// </summary>
        /// <param name="x">The Xml Object that will be inserted too.</param>
        /// <param name="xPathExpression">XPath of the Element to add</param>
        /// <param name="valueToAdd">The value of the new Element</param>
        /// <param name="namespaces">In format prefix::NameSpaceURI</param>
        /// <returns></returns>
        public static XElement EditAttributeInXPath(this XElement x, string xPathExpression, string valueToAdd, List<string> namespaces)
        {
            //Params
            List<string> Params = new List<string>();
            Params.Add(string.Format("XElement x:{0}", x.ToString()));
            Params.Add(string.Format("String xPathExpression:{0}", xPathExpression));
            Params.Add(string.Format("String valueToAdd:{0}", valueToAdd));
            Params.Add(string.Format("List<String>  namespaces:{0}", StringHelper.ListOfStringToString(namespaces, true)));
            try
            {
                List<string> lst = new List<string>();
                XmlReader reader = XmlReader.Create(new StringReader(x.ToString()));
                XElement root = XElement.Load(reader);
                XmlNameTable nameTable = reader.NameTable;
                XmlNamespaceManager nsm = new XmlNamespaceManager(nameTable);
                foreach (string t in namespaces)
                {
                    lst = StringHelper.StringToListOfString(t, "::", true, false);
                    nsm.AddNamespace(lst[0], lst[1]);
                }
                return EditAttributeInXPath(x, xPathExpression, nsm, valueToAdd);
            }
            catch (IRDev.Library.ExpandedException.Common.ExpandedException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                IRDev.Library.ExpandedException.Common.ExpandedException ee = IRDev.Library.ExpandedException.Factory.ExpandedExceptionFactory.CreateAndReturnExpandedException(ex, StringHelper.ListOfStringToString(Params, true), "XPathHelper", "EditAttributeInXPath");
                throw ee;
            }
        }
        /// <summary>
        /// EditAttributeInXpath
        /// </summary>
        /// <param name="x"></param>
        /// <param name="xPath"></param>
        /// <param name="nsm"></param>
        /// <param name="valueToAdd"></param>
        /// <returns></returns>
        public static XElement EditAttributeInXPath(this XElement x, string xPath, XmlNamespaceManager nsm, string valueToAdd)
        {
            //Params
            List<string> Params = new List<string>();
            Params.Add(string.Format("XElement x:{0}", x.ToString()));
            Params.Add(string.Format("String xPath:{0}", xPath));
            Params.Add(string.Format("XmlNamespaceManager nsm:{0}", nsm.ToString()));
            Params.Add(string.Format("String valueToAdd:{0}", valueToAdd));
            try
            {
                if (xPath.Contains("/"))
                {
                    bool useLinqStyleXPath = !xPath.Contains("local-name");
                    string xPathForLinq = (useLinqStyleXPath ? xPath : CreateFormattedLinqXPathFromInstanceXPath(xPath, nsm));
                    string xElementContainerXPath = xPathForLinq.Substring(0, xPathForLinq.LastIndexOf("/") - 1);
                    string xAttributeName = xPathForLinq.Substring(xPathForLinq.LastIndexOf("/") + 1).Replace("@", "");
                    x.XPathSelectElement(xElementContainerXPath, nsm).Attribute(xAttributeName).Value = valueToAdd;
                }
                return x;
            }
            catch (IRDev.Library.ExpandedException.Common.ExpandedException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                IRDev.Library.ExpandedException.Common.ExpandedException ee = ex.CreateAndReturnExpandedException(StringHelper.ListOfStringToString(Params, true), "XPathHelper", "EditAttributeInXPath");
                throw ee;
            }
        }
        /// <summary>
        /// EditAttributeInXPath
        /// </summary>
        /// <param name="uri"></param>
        /// <param name="xPath"></param>
        /// <param name="valueToAdd"></param>
        /// <param name="namespaces">In format prefix::NameSpaceURI</param>
        /// <returns>String of XML DOcument</returns>
        public static string EditAttributeInXPath(this string uri, string xPath, string valueToAdd, List<string> namespaces)
        {
            //Params
            List<string> Params = new List<string>();
            Params.Add(string.Format("String uri:{0}", uri));
            Params.Add(string.Format("String xPath:{0}", xPath));
            Params.Add(string.Format("String valueToAdd:{0}", valueToAdd));
            Params.Add(string.Format("List<String>  namespaces:{0}", StringHelper.ListOfStringToString(namespaces, true)));
            try
            {
                XElement xe = XElement.Load(uri);
                return EditAttributeInXPath(xe, xPath, valueToAdd, namespaces).ToString();
            }
            catch (IRDev.Library.ExpandedException.Common.ExpandedException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                IRDev.Library.ExpandedException.Common.ExpandedException ee = IRDev.Library.ExpandedException.Factory.ExpandedExceptionFactory.CreateAndReturnExpandedException(ex, StringHelper.ListOfStringToString(Params, true), "XPathHelper", "EditAttributeInXPath");
                throw ee;
            }
        }
        /// <summary>
        /// ReplaceOrAddIfMissingElementInElementUsingXPath
        /// </summary>
        /// <param name="x"></param>
        /// <param name="xPathExpression"></param>
        /// <param name="valueToAdd"></param>
        /// <param name="ls"></param>
        /// <returns></returns>
        public static XElement ReplaceOrAddIfMissingElementInElementUsingXPath(this XElement x, string xPathExpression, string valueToAdd, List<string> namespaces)
        {
            //Params
            List<string> Params = new List<string>();
            Params.Add(string.Format("XElement x:{0}",x));
            Params.Add(string.Format("String xPathExpression:{0}", xPathExpression));
            Params.Add(string.Format("String valueToAdd:{0}", valueToAdd));
            Params.Add(string.Format("List<String> namespaces:{0}", StringHelper.ListOfStringToString(namespaces, true)));
            try
            {
                List<string> lst = new List<string>();
                XmlReader reader = XmlReader.Create(new StringReader(x.ToString()));
                XElement root = XElement.Load(reader);
                XmlNameTable nameTable = reader.NameTable;
                XmlNamespaceManager nsm = new XmlNamespaceManager(nameTable);
                foreach (string t in namespaces)
                {
                    lst = StringHelper.StringToListOfString(t, "::", true, false);
                    nsm.AddNamespace(lst[0], lst[1]);
                }
                return ReplaceOrAddIfMissingElementInElementUsingXPath(x, xPathExpression, valueToAdd, nsm);
            }
            catch (IRDev.Library.ExpandedException.Common.ExpandedException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                IRDev.Library.ExpandedException.Common.ExpandedException ee = IRDev.Library.ExpandedException.Factory.ExpandedExceptionFactory.CreateAndReturnExpandedException(ex, StringHelper.ListOfStringToString(Params, true), "XPathHelper", "ReplaceOrAddIfMissingElementInElementUsingXPath");
                throw ee;
            }
        }
        /// <summary>
        /// ReplaceOrAddIfMissingElementInElementUsingXPath
        /// </summary>
        /// <param name="x"></param>
        /// <param name="xPathExpression"></param>
        /// <param name="nsm"></param>
        /// <param name="valueToAdd"></param>
        /// <returns></returns>
        public static XElement ReplaceOrAddIfMissingElementInElementUsingXPath(this XElement x, string xPathExpression,  string valueToAdd, XmlNamespaceManager nsm)
        {
            //Params
            List<string> Params = new List<string>();
            Params.Add(string.Format("XElement x:{0}", x.ToString()));
            Params.Add(string.Format("String xPathExpression:{0}", xPathExpression));
            Params.Add(string.Format("String valueToAdd:{0}", valueToAdd));
            Params.Add(string.Format("XmlNamespaceManager nsm:{0}", nsm.ToString()));
            try
            {
                bool useLinqStyleXPath = !xPathExpression.Contains("local-name");
                string xPathForLinq = (useLinqStyleXPath ? xPathExpression : CreateFormattedLinqXPathFromInstanceXPath(xPathExpression, nsm));
                if (x.XPathSelectElements(xPathForLinq, nsm).Count() > 0)
                {
                    x.XPathSelectElement(xPathForLinq, nsm).Value = valueToAdd;
                }
                else
                {
                    return AddElementToElementUsingXPath(x, xPathForLinq, valueToAdd, nsm);
                }
                return x;
            }
            catch (IRDev.Library.ExpandedException.Common.ExpandedException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                IRDev.Library.ExpandedException.Common.ExpandedException ee = IRDev.Library.ExpandedException.Factory.ExpandedExceptionFactory.CreateAndReturnExpandedException(ex, StringHelper.ListOfStringToString(Params, true), "XPathHelper", "ReplaceOrAddIfMissingElementInElementUsingXPath");
                throw ee;
            }
        }
        /// <summary>
        /// AddElementToElementUsingXPath
        /// </summary>
        /// <param name="x"></param>
        /// <param name="xPath"></param>
        /// <param name="xmlToAdd"></param>
        /// <param name="nsm"></param>
        /// <returns>Edited XElement</returns>
        public static XElement AddElementToElementUsingXPath(this XElement x, string xPathExpression, string valueToAdd, XmlNamespaceManager nsm)
        {
            //Params
            List<string> Params = new List<string>();
            Params.Add(string.Format("XElement x:{0}", x.ToString()));
            Params.Add(string.Format("String xPathExpression:{0}", xPathExpression));
            Params.Add(string.Format("String valueToAdd:{0}", valueToAdd));
            Params.Add(string.Format("XmlNamespaceManager nsm:{0}", nsm.ToString()));
            try
            {
                bool useLinqStyleXPath = !xPathExpression.Contains("local-name");
                List<string> ls = (useLinqStyleXPath ? StringHelper.StringToListOfString(xPathExpression, "/", true, true) : StringHelper.StringToListOfString(xPathExpression, "/*", true, true));
                ls.Reverse();
                List<ElementSet> les = new List<ElementSet>();
                string currentPath = string.Empty;
                XElement xe;
                ElementSet es;
                string xPathForLinq = (useLinqStyleXPath ? xPathExpression : CreateFormattedLinqXPathFromInstanceXPath(xPathExpression, nsm));
                string reparse = string.Empty;
                foreach (string s in ls)
                {
                    currentPath = (useLinqStyleXPath ? "/*" + CreateFormattedInstanceElementFromLinqXPath(s, nsm) : "/*" + s);
                    es = new ElementSet(currentPath);
                    if (x.XPathSelectElements(xPathForLinq, nsm).Count() > 0)
                    {
                        xe = XElement.Parse(valueToAdd.Replace(":", "___"));
                        x.XPathSelectElement(xPathForLinq, nsm).Add(CreateXElementFromNameList(xe, les));
                        reparse = x.ToString().Replace("___", ":");
                        x = XElement.Parse(reparse);
                        return x;
                    }
                    else
                    {
                        currentPath = "/" + s;
                        es = new ElementSet(currentPath);
                        les.Add(es);
                    }
                }
                return x;
            }
            catch (IRDev.Library.ExpandedException.Common.ExpandedException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                IRDev.Library.ExpandedException.Common.ExpandedException ee = IRDev.Library.ExpandedException.Factory.ExpandedExceptionFactory.CreateAndReturnExpandedException(ex, StringHelper.ListOfStringToString(Params, true), "XPathHelper", "AddElementToElementUsingXPath");
                throw ee;
            }
        }
        /// <summary>
        ///  CreateFormattedInstanceElementFromLinqXPath
        ///  Only handles 1 Element at a time. 
        ///  Add "handles Element String"
        ///  input /MyName or /ns0:MyName
        /// </summary>
        /// <param name="LinqXPath"></param>
        /// <param name="nsm"></param>
        /// <returns>formatted element example: [local-name()='name' and namespace-uri()='']</returns>
        public static string CreateFormattedInstanceElementFromLinqXPath(this string LinqXPath, XmlNamespaceManager nsm)
        {
            //Params
            List<string> Params = new List<string>();
            Params.Add(string.Format("String LinqXPath:{0}", LinqXPath));
            Params.Add(string.Format("XmlNamespaceManager nsm:{0}", nsm.ToString()));
            try
            {
                List<string> ls = StringHelper.StringToListOfString(LinqXPath, ":", true, true);
                return (ls.Count > 1 ? "[local-name()='" + ls[1] + "' and namespace-uri()='" + nsm.LookupNamespace(ls[0]) + "']" : "[local-name()='" + ls[1] + "' and namespace-uri()='']");
            }
            catch (IRDev.Library.ExpandedException.Common.ExpandedException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                IRDev.Library.ExpandedException.Common.ExpandedException ee = IRDev.Library.ExpandedException.Factory.ExpandedExceptionFactory.CreateAndReturnExpandedException(ex, StringHelper.ListOfStringToString(Params, true), "XPathHelper", "CreateFormattedInstanceElementFromLinqXPath");
                throw ee;
            }
        }
        /// <summary>
        /// Can take in long path 
        /// /*[local-name()='name' and namespace-uri()='']/*[local-name()='name2' and namespace-uri()='']/*[local-name()='name3' and namespace-uri()='']
        /// </summary>
        /// <param name="xPath"></param>
        /// <param name="nsm"></param>
        /// <returns>/name/name2/name3</returns>
        private static string CreateFormattedLinqXPathFromInstanceXPath(this string xPath, XmlNamespaceManager nsm)
        {
            //Params
            List<string> Params = new List<string>();
            Params.Add(string.Format("String xPath:{0}", xPath));
            Params.Add(string.Format("XmlNamespaceManager nsm:{0}", nsm.ToString()));
            try
            {
                ElementSet es;
                StringBuilder sb = new StringBuilder(".");
                foreach (string ss in StringHelper.StringToListOfString(xPath, "/*", true, true))
                {
                    es = new ElementSet("/*" + ss);
                    if (es.CurrentElement.Contains(":"))
                    {
                        sb.Append("/" + es.CurrentElement);
                    }
                    else
                    {
                        sb.Append("/" + (es.hasNameSpace ? nsm.LookupPrefix(es.NameSpace) + ":" : string.Empty) + es.CurrentElement);
                    }
                }
                return sb.ToString();
            }
            catch (IRDev.Library.ExpandedException.Common.ExpandedException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                IRDev.Library.ExpandedException.Common.ExpandedException ee = IRDev.Library.ExpandedException.Factory.ExpandedExceptionFactory.CreateAndReturnExpandedException(ex, StringHelper.ListOfStringToString(Params, true), "XPathHelper", "CreatedFormattedLinqXPathFromInstanceXPath");
                throw ee;
            }
        }
        /// <summary>
        /// CreateXElementFromNameList
        /// </summary>
        /// <param name="x"></param>
        /// <param name="les"></param>
        /// <returns></returns>
        public static XElement CreateXElementFromNameList(this XElement x, List<ElementSet> les)
        {
            //Params
            List<string> Params = new List<string>();
            Params.Add(string.Format("XElement x:{0}", x.ToString()));
            try
            {
                XElement xe = x;
                foreach (ElementSet es in les)
                {
                    Params.Add(string.Format("EachElement les:{0}", es.NameSpace));
                    if (es.hasNameSpace)
                    {
                        x = (es.hasNameSpace ? new XElement(es.xNameSpace + es.CurrentElement) : new XElement(es.CurrentElement));
                    }
                    x.Add(xe);
                }
                return x;
            }
            catch (IRDev.Library.ExpandedException.Common.ExpandedException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                IRDev.Library.ExpandedException.Common.ExpandedException ee = IRDev.Library.ExpandedException.Factory.ExpandedExceptionFactory.CreateAndReturnExpandedException(ex, StringHelper.ListOfStringToString(Params, true), "XPathHelper", "CreateXElementFromNameList");
                throw ee;
            }
        }
        /// <summary>
        /// CreateXElementFromXPath
        /// </summary>
        /// <param name="x"></param>
        /// <param name="xPath"></param>
        /// <returns>Returns x with the new Element</returns>
        public static XElement CreateXElementFromXPath(this XElement x, string xPath)
        {
            //Params
            List<string> Params = new List<string>();
            Params.Add(string.Format("XElement x:{0}", x.ToString()));
            Params.Add(string.Format("String xPath:{0}", xPath));
            try
            {
                XElement xeNew = null;
                XElement xeBase = null;
                List<string> ls = StringHelper.StringToListOfString(xPath, "/*", true, true);
                ls.Reverse();
                foreach (string s in ls)
                {
                    if (xeNew != null)
                    {
                        xeBase = xeNew;
                        //If it isn't the element to Add
                        ElementSet es = new ElementSet("/*" + s);
                        if (es.hasNameSpace)
                        {
                            xeNew = new XElement(es.xNameSpace + es.CurrentElement);
                        }
                        else
                        {
                            xeNew = new XElement(es.CurrentElement);
                        }
                        xeNew.Add(xeBase);
                    }
                    else
                    {
                        ElementSet es = new ElementSet("/*" + s);
                        if (es.hasNameSpace)
                        {
                            xeNew = new XElement(es.xNameSpace + es.CurrentElement);
                        }
                        else
                        {
                            xeNew = new XElement(es.CurrentElement);
                        }
                    }
                }
                x.Add(xeNew);
                return x;
            }
            catch (IRDev.Library.ExpandedException.Common.ExpandedException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                IRDev.Library.ExpandedException.Common.ExpandedException ee = IRDev.Library.ExpandedException.Factory.ExpandedExceptionFactory.CreateAndReturnExpandedException(ex, StringHelper.ListOfStringToString(Params, true), "XPathHelper", "CreateXElementFromXPath");
                throw ee;
            }
        }
        /// <summary>
        /// GetXNameSpaceNameLocal
        /// </summary>
        /// <param name="xPath"></param>
        /// <returns></returns>
        public static string GetXNameSpaceNameLocal(this string xPath)
        {
            //Params
            List<string> Params = new List<string>();
            Params.Add(string.Format("String xPath:{0}", xPath));
            try
            {
                if (xPath.Contains("/*") && xPath.Contains("'") && xPath.Contains(" and "))
                {
                    if (xPath.IndexOf("/*") != xPath.LastIndexOf("/*"))
                    {
                        return "";
                    }
                    else
                    {
                        return xPath.Substring(xPath.LastIndexOf("=") + 1, xPath.LastIndexOf("'") - (xPath.LastIndexOf("=") + 1)).Replace("'", "").Trim();
                    }
                }
                else
                {
                    return "";
                }
            }
            catch (IRDev.Library.ExpandedException.Common.ExpandedException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                IRDev.Library.ExpandedException.Common.ExpandedException ee = IRDev.Library.ExpandedException.Factory.ExpandedExceptionFactory.CreateAndReturnExpandedException(ex, StringHelper.ListOfStringToString(Params, true), "XPathHelper", "GetXNameSpaceNameLocal");
                throw ee;
            }
        }
        /// <summary>
        /// GetElementNameLocal
        /// </summary>
        /// <param name="xPath"></param>
        /// <returns></returns>
        public static string GetElementNameLocal(this string xPath)
        {
            //Params
            List<string> Params = new List<string>();
            Params.Add(string.Format("String xPath:{0}", xPath));
            try
            {
                if (xPath.Contains("/*") && xPath.Contains("=") && xPath.Contains("'") && xPath.Contains("uri"))
                {
                    if (xPath.IndexOf("/*") != xPath.LastIndexOf("/*"))
                    {
                        return "MORE_THAN_1_ELEMENT_FOUND";
                    }
                    else
                    {
                        return xPath.Substring(xPath.IndexOf("'") + 1, xPath.IndexOf(" and ") - (xPath.IndexOf("'") + 1)).Replace("'", "").Trim();
                    }
                }
                else
                {
                    return "IMPROPERLY_FORMED_XPATH";
                }
            }
            catch (IRDev.Library.ExpandedException.Common.ExpandedException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                IRDev.Library.ExpandedException.Common.ExpandedException ee = IRDev.Library.ExpandedException.Factory.ExpandedExceptionFactory.CreateAndReturnExpandedException(ex, StringHelper.ListOfStringToString(Params, true), "XPathHelper", "GetElementNameLocal");
                throw ee;
            }
        }
        /// <summary>
        /// AddElementFromXPath
        /// </summary>
        /// <param name="xElementUri"></param>
        /// <param name="xPathExpression"></param>
        /// <param name="valueToAdd"></param>
        /// <param name="namespaces"></param>
        /// <returns></returns>
        public static string AddElementFromXPath(this string xElementUri, string xPathExpression, string valueToAdd, List<string> namespaces)
        {
            //Params
            List<string> Params = new List<string>();
            Params.Add(string.Format("String xElementUri:{0}", xElementUri));
            Params.Add(string.Format("String xPathExpression:{0}", xPathExpression));
            Params.Add(string.Format("String valueToAdd:{0}", valueToAdd));
            Params.Add(string.Format("List<String> namespaces:{0}", StringHelper.ListOfStringToString(namespaces, true)));
            try
            {
                XElement xe = XElement.Load(xElementUri);
                return AddElementFromXPath(xe, xPathExpression, valueToAdd, namespaces).ToString();
            }
            catch (IRDev.Library.ExpandedException.Common.ExpandedException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                IRDev.Library.ExpandedException.Common.ExpandedException ee = IRDev.Library.ExpandedException.Factory.ExpandedExceptionFactory.CreateAndReturnExpandedException(ex, StringHelper.ListOfStringToString(Params, true), "XPathHelper", "AddElementFromXPath");
                throw ee;
            }
        }
        /// <summary>
        /// ReplaceOrAddIfMissingElementInElementUsingXPath
        /// </summary>
        /// <param name="xElementUri"></param>
        /// <param name="xPathExpression"></param>
        /// <param name="valueToAdd"></param>
        /// <param name="namespaces"></param>
        /// <returns>Xml String for Entire XElement object.</returns>
        internal static string ReplaceOrAddIfMissingElementInElementUsingXPath(this string xElementUri, string xPathExpression, string valueToAdd, List<string> namespaces)
        {
            //Params
            List<string> Params = new List<string>();
            Params.Add(string.Format("String xElementUri:{0}", xElementUri));
            Params.Add(string.Format("String xPathExpression:{0}", xPathExpression));
            Params.Add(string.Format("String valueToAdd:{0}", valueToAdd));
            Params.Add(string.Format("List<String> namespaces:{0}", StringHelper.ListOfStringToString(namespaces, true)));
            try
            {
                XElement xe = XElement.Load(xElementUri);
                return ReplaceOrAddIfMissingElementInElementUsingXPath(xe, xPathExpression, valueToAdd, namespaces).ToString();
            }
            catch (IRDev.Library.ExpandedException.Common.ExpandedException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                IRDev.Library.ExpandedException.Common.ExpandedException ee = IRDev.Library.ExpandedException.Factory.ExpandedExceptionFactory.CreateAndReturnExpandedException(ex, StringHelper.ListOfStringToString(Params, true), "XPathHelper", "ReplaceOrAddIfMissingElementInElementUsingXPath");
                throw ee;
            }
        }
    }
}
